#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <shmem.h>
#include <cJSON.h>

#define DEV_UART "/dev/ttyUSB0"
#define ENV_LEN sizeof(struct env_info)
#define CONVER_ENV_LEN sizeof(struct conver_env_info)

struct env_info
{
    uint8_t head[3]; //标识位st:
    uint8_t type;    //数据类型
    uint8_t snum;    //房间编号
    uint8_t temp[2]; //温度
    uint8_t hum[2];  //湿度
    uint8_t x;       //三轴信息
    uint8_t y;
    uint8_t z;
    uint32_t ill; //光照
    uint32_t bet; //电池电量
    uint32_t adc; //电位器信息
};

static struct shm_param para; //创建共享内存结构体变量

float temperature; //温度
float humidity;    //湿度
int ill;           //光照
int fd;            //打开的设备文件

float dota_atof(char unitl);
int dota_atoi(const char *cDecade);
float dota_adc(unsigned int ratio);

union val_t {
    int b_val;   //bool类型存储空间
    int i_val;   //整形值存储空间
    float f_val; //浮点值存储空间
};

struct std_node
{
    int key;             //唯一键值
    int type;            //数据点类型
    int dev_type;        //属于哪个设备
    union val_t old_val; //旧值
    union val_t new_val; //新值
    int ret;             //采集成功0，采集失败-1,默认-1
};

//消息队列结构体
struct msgbuf
{
    long mtype;
    char mdata[256];
};
struct std_node *shm_create() //创建共享内存
{
    int ret = -1;
    ret = shm_init(&para, "m0", sizeof(struct std_node) * 3);
    if (ret < 0)
    {
        return NULL;
    }

    struct std_node *addr = shm_getaddr(&para);
    if (addr == NULL)
    {
        return NULL;
    }

    return addr;
}

void serial_init(int fd)
{
    struct termios options;
    tcgetattr(fd, &options);
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~CSIZE;
    options.c_cflag &= ~CRTSCTS;
    options.c_cflag |= CS8;
    options.c_cflag &= ~CSTOPB;
    options.c_iflag |= IGNPAR;
    options.c_iflag &= ~(ICRNL | IXON);
    options.c_oflag = 0;
    options.c_lflag = 0;

    cfsetispeed(&options, B115200);
    cfsetospeed(&options, B115200);
    tcsetattr(fd, TCSANOW, &options);
}

void recv_pthread(void *arg)
{
    int key;
    int val;
    unsigned char cmd;

    cJSON *root = NULL;
    cJSON *item = NULL;
    cJSON *recv_root = NULL;

    struct msgbuf send_buf;
    struct msgbuf recv_buf;

    send_buf.mtype = 1;
    recv_buf.mtype = 1;

    while (1)
    {
        if (msg_queue_recv("m0_recv", &recv_buf, sizeof(recv_buf), 0, 0) > 0)
        {
            recv_root = cJSON_Parse(recv_buf.mdata);
            item = cJSON_GetObjectItem(recv_root, "data");
            item = cJSON_GetObjectItem(item, "key");
            key = atoi(cJSON_Print(item));

            item = cJSON_GetObjectItem(recv_root, "data");
            item = cJSON_GetObjectItem(item, "val");
            val = atoi(item->valuestring);

            printf("%d %d\n", key, val);
        }
        else
        {
            perror("recv error:");
            break;
        }

        if (key == 4)   //控制灯
        {
            if (val == 0)
            {
                cmd = 0xA0;
            }
            else if (val == 1)
            {
                cmd = 0xA1;
            }
        }
        else if (key == 5) //控制蜂鸣器
        {
            if (val == 0)
            {
                cmd = 0x90;
            }
            else if (val == 1)
            {
                cmd = 0x91;
            }
        }
        else if (key == 6)  //风扇
        {
            if (val == 0)
            {
                cmd = 0x80;
            }
            else if (val == 1)
            {
                cmd = 0x81;
            }
            else if (val == 2)
            {
                cmd = 0x82;
            }
            else if (val == 3)
            {
                cmd = 0x83;
            }
        }

        write(fd, &cmd, 1);

        cJSON *root = cJSON_CreateObject();
        cJSON_AddItemToObject(root, "type", cJSON_CreateNumber(2));
        cJSON_AddItemToObject(root, "result", cJSON_CreateNumber(0));
        cJSON_AddItemToObject(root, "type", cJSON_CreateString("控制成功"));

        strcpy(send_buf.mdata, cJSON_Print(root));

        if (msg_queue_send("m0_send", &send_buf, sizeof(send_buf), 0) < 0)
        {
            printf("msg_queue_send error\n");
            return -1;
        }
    }

    pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
    pthread_t tid;
    int nbytes = 0;
    struct env_info envinfo; //原始数据

    if (pthread_create(&tid, NULL, recv_pthread, NULL) != 0)
    {
        perror("pthread_create err.");
        return -1;
    }
    pthread_detach(tid);
    if ((fd = open(DEV_UART, O_RDWR)) < 0)
    {
        perror("open uart err\n");
        return -1;
    }

    serial_init(fd);

    struct std_node *addr = shm_create();

    while (1)
    {
        nbytes = read(fd, &envinfo, ENV_LEN);
        if (nbytes == ENV_LEN)
        {
            // printf("raw data ill=%d, x=%d, y=%d, z=%d\n",
            //        envinfo.ill, envinfo.x, envinfo.y, envinfo.z);
        }
        else
        {
            printf("err data");
        }

        temperature = envinfo.temp[0] + dota_atof(envinfo.temp[1]);
        humidity = envinfo.hum[0] + dota_atof(envinfo.hum[1]);
        ill = envinfo.ill;

        for (int i = 0; i < 3; i++)
        {
            addr[i].key = i;      //唯一键值
            addr[i].type = 1;     //数据点类型
            addr[i].dev_type = 1; //属于哪个设备
            if (i == 0)           //温度
            {
                addr[i].old_val.f_val = addr[i].new_val.f_val;

                addr[i].new_val.f_val = temperature; //新值
                printf("temperature old = %0.2f\n", addr[i].old_val.f_val);
                printf("temperature new = %0.2f\n", addr[i].new_val.f_val);
            }
            else if (i == 1)
            {
                addr[i].old_val.f_val = addr[i].new_val.f_val;

                addr[i].new_val.f_val = humidity; //新值
                printf("humidity old = %0.2f\n", addr[i].old_val.f_val);
                printf("humidity new = %0.2f\n", addr[i].new_val.f_val);
            }
            else if (i == 2)
            {
                addr[i].old_val.i_val = addr[i].new_val.i_val;

                addr[i].new_val.i_val = ill; //新值

                printf("ill old = %d\n", addr[i].old_val.i_val);
                printf("ill new = %d\n", addr[i].new_val.i_val);
            }

            addr[i].ret = 0;
        }
        // printf("conver temperature=%0.2f, humidity=%0.2f, ill=%d\n",
        //        temperature, humidity, ill);
    }

    return 0;
}

float dota_atof(char unitl)
{
    if (unitl > 100)
    {
        return unitl / 1000.0;
    }
    else if (unitl > 10)
    {
        return unitl / 100.0;
    }
    else
    {
        return unitl / 10.0;
    }
}

int dota_atoi(const char *cDecade)
{
    int result = 0;
    if (' ' != cDecade[0])
    {
        result = (cDecade[0] - 48) * 10;
    }
    result += cDecade[1] - 48;
    return result;
}

float dota_adc(unsigned int ratio)
{
    return ((ratio * 3.3) / 1024);
}